﻿namespace WebPacker.Tool
{
	using System.IO;
	using NXml.Serialization;
	using NXml.Serialization.Mappings;
	using NXml.Serialization.Mappings.Providers;
	using WebPacker.Configuration;
	using WebPacker.Filters;
	using WebPacker.VersionGenerators;

	internal class Configuration
	{
		public string BasePath { get; set; }

		public string Output { get; set; }

		public string MetaFileName { get; set; }

		public string VersionGeneratorName { get; set; }

		public IFilter[] Filters { get; set; }

		public IVersionGenerator[] VersionGenerators { get; set; }

		public static Configuration GetDefaults()
		{
			return new Configuration
			{
				Filters = new IFilter[]
				{
					new YuiCssMinifier { Name = "css" },
					new YuiJavascriptMinifier { Name = "js" }
				},
				VersionGenerators = new IVersionGenerator[]
				{
					new Md5VersionGenerator(),
					new LastModifiedVersionGenerator(),
					new ManualVersionGenerator(),
					new HashCodeVersionGenerator()
				},
				VersionGeneratorName = "manual"
			};
		}

		public static Configuration OpenConfiguration(string configFile)
		{
			var defaults = GetDefaults();

			if (configFile == null)
			{
				return defaults;
			}

			if (!File.Exists(configFile))
			{
				throw ToolException.FileNotFound(configFile);
			}

			var context = new XmlSerializerContext
			{
				TypeResolver = new WebPackerTypeResolver(),

				MappingProvider = new XmlLambdaMappingProvider(new WebPackerMappingProvider())
				{
					Mapper = (type) =>
					{
						if (type == typeof(Configuration))
						{
							return new XmlObjectMapping(type)
							{
								Properties = new XmlPropertyMapping[]
								{
									new XmlPropertyMapping(typeof(string), "Output")
									{
										XmlName = "output",
										MappingNode = XmlMappingNode.Attribute
									},
									new XmlPropertyMapping(typeof(string), "VersionGeneratorName")
									{
										XmlName = "versionGenerator",
										MappingNode = XmlMappingNode.Attribute
									},
									new XmlPropertyMapping(typeof(IFilter[]), "Filters")
									{
										XmlName = "filters",
										MappingNode = XmlMappingNode.Element
									},
									new XmlPropertyMapping(typeof(IVersionGenerator[]), "VersionGenerators")
									{
										XmlName = "versionGenerators",
										MappingNode = XmlMappingNode.Element
									}
								}
							};
						}

						return null;
					}
				}
			};

			var serializer = new XmlSerializer<Configuration>(context, "web.packer", false);

			Configuration cfg;

			using (var stream = File.OpenRead(configFile))
			{
				cfg = serializer.Deserialize(stream);
			}

			if (cfg.VersionGenerators == null)
			{
				cfg.VersionGenerators = defaults.VersionGenerators;
			}

			if (cfg.VersionGeneratorName == null)
			{
				cfg.VersionGeneratorName = defaults.VersionGeneratorName;
			}

			return cfg;
		}
	}
}
